package importadodebookworm;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.LinkedList;

import excecoes.NaoConseguiuObterResenhasDaRevishException;



public class GetReviewDataFromApi implements InterfaceGetBookReviewData
{
	
	/**
	 * gets all book reviews from Revish API that match the searchArguments with their respective values.
	 * different from the getBookReviewsFromRevishAPI method, it really returns all the reviews from search, not just 20 at a maximum 
	 */
	public LinkedList<Review> getAllBookReviewsFromRevishAPI(LinkedList<String> searchArguments, LinkedList<String> argumentsValue) throws NaoConseguiuObterResenhasDaRevishException
	{
		String XMLWithReviewsFromBook = getXMLWithReviewsFromRevishAPI(searchArguments, argumentsValue);
		GetTagContent getsTagContentFromXML = new GetTagContent();
		String totalReviews = getsTagContentFromXML.getTagContent(XMLWithReviewsFromBook, "totalreviews");
		//now we have he total of reviews from our tag. let's add as an argument of our search
		//the limit of reviews. By default, it's 20. But we don't want 20...
		searchArguments.add("limit");
		argumentsValue.add(totalReviews);
		return this.getBookReviewsFromRevishAPI(searchArguments, argumentsValue);
		
	}
	
	/**
	 * sometimes we want just the number of reviews found in a search we make, so this method is just for these situations.
	 */
	public int getNumberOfBookReviewsFromRevishAPI(LinkedList<String> searchArguments, LinkedList<String> argumentsValue) throws NaoConseguiuObterResenhasDaRevishException
	{
		String XMLWithReviewsFromBook = getXMLWithReviewsFromRevishAPI(searchArguments, argumentsValue);
		GetTagContent getsTagContentFromXML = new GetTagContent();
		String totalReviews = getsTagContentFromXML.getTagContent(XMLWithReviewsFromBook, "totalreviews");
		if(totalReviews.length() > 0)
		{
			return Integer.valueOf(totalReviews);
		}
		else
		{
			return 0;
		}
	}
	
	/**
	 * apart from getAllBookReviewsFromRevishAPI, it only returns 20 reviews at a maximum based
	 * on the search criteria. It's for quick searches.
	 */
	public LinkedList<Review> getBookReviewsFromRevishAPI(LinkedList<String> searchArguments, LinkedList<String> argumentsValue) throws NaoConseguiuObterResenhasDaRevishException
	{
		/* note: the parameters in this method are arguments to add in the search for book reviews */
		
		String XMLWithReviewsFromBook = getXMLWithReviewsFromRevishAPI(searchArguments, argumentsValue);
		LinkedList<String> separateXMLFromEachReview = getXMLFromEachReview(XMLWithReviewsFromBook);
		LinkedList<Review> bookReviews = getReviewsFromXMLFromEachReview(separateXMLFromEachReview);
		return bookReviews;
	}
	
	/**
	 * it asks Revish's API to make a search. The API will return a XML as result for the search which is return by this method. 
	 * @param searchArguments the arguments to use in the API search for book reviews. Possible values are
	 * "user", "tag", "isbn", "title", "author" and "publisher"
	 * @param argumentsValue the respective arguments' values. 
	 * @return
	 */
	private String getXMLWithReviewsFromRevishAPI(LinkedList<String> searchArguments, LinkedList<String> argumentsValue) throws NaoConseguiuObterResenhasDaRevishException
	{
		
		//first, let's create the URL request for searching book reviews with it's arguments and values
		String urlRequest = "http://api.revish.com/getReviews?apikey=5828ca0b04ec8f0ff84e81b184424d1a";
		//the request isn't complete. It needs arguments and their values which we'll include right now:
		for(int i = 0; i < searchArguments.size(); i++)
		{
			String argumentName = searchArguments.get(i);
			String argumentValue = argumentsValue.get(i);
			if(argumentName.compareTo("user") == 0)
			{
				argumentValue = GetReviewDataFromApi.reformatUsernameToQuery(argumentValue);
			}
			urlRequest = urlRequest + "&" + argumentName + "=" +  argumentValue;
		}
		//let's just replace all spaces from our urlRequest for a "%20" for our query
		String urlRequestFormatted= urlRequest.replaceAll(" ", "%20");
		
		//now, let's request Revish for book reviews
		try
		{
			URL resource = new URL(urlRequestFormatted);
			HttpURLConnection connection = (HttpURLConnection) resource.openConnection();
			connection.setRequestMethod("GET");
			connection.setDoOutput(true);
			connection.connect();
			InputStream inputStream = connection.getInputStream();
			Reader streamReader = new InputStreamReader(inputStream);
			BufferedReader buffer = new BufferedReader(streamReader);
			String readLine = buffer.readLine();
			String xml = "";
			while(readLine != null)
			{
				xml = xml + readLine;
				readLine = buffer.readLine();
			}
			connection.disconnect();
			return xml;
		}
		catch(MalformedURLException exc)
		{
			throw new NaoConseguiuObterResenhasDaRevishException();
		}
		catch(IOException exc)
		{
			System.out.println(exc);
			System.out.println("connection problems...");
			throw new NaoConseguiuObterResenhasDaRevishException();
		}
	}
	
	
	
	private LinkedList<String> getXMLFromEachReview(String XMLWithReviewsFromBook)
	{
		GetTagContent getContent = new GetTagContent();
		LinkedList<String> XMLFromEachReview = 
				getContent.getTagContentsMultipleOccurrences(XMLWithReviewsFromBook, "review");
		return XMLFromEachReview;
	}
	
	
	private Review getReviewFromXML(String XMLOfOneReview)
	{
		Review review = new Review();
		GetTagContent getContent = new GetTagContent();
		
		String idInString = getContent.getTagContent(XMLOfOneReview, "reviewid");
		int reviewId = Integer.valueOf(idInString);
		
		String isbnInString = getContent.getTagContent(XMLOfOneReview, "isbn");
		String isbn = isbnInString;
		
		String bookTitle = getContent.getTagContent(XMLOfOneReview, "booktitle");
		LinkedList<String> authors = getContent.getTagContentsMultipleOccurrences(XMLOfOneReview, "author");
		String reviewer = getContent.getTagContent(XMLOfOneReview, "reviewer");
		String reviewTitle = getContent.getTagContent(XMLOfOneReview, "reviewtitle");
		String publisher = getContent.getTagContent(XMLOfOneReview, "publisher");
		String reviewDate = getContent.getTagContent(XMLOfOneReview, "reviewdate");
		String ratingInString = getContent.getTagContent(XMLOfOneReview, "rating");
		int rating = Integer.valueOf(ratingInString);
		String urlReview = getContent.getTagContent(XMLOfOneReview, "url");
		String smallCover = getContent.getTagContent(XMLOfOneReview, "smallcover");
		String mediumCover = getContent.getTagContent(XMLOfOneReview, "mediumcover");
		LinkedList<String> linksWhereToBuyBook = new LinkedList<String>();
		String linkAmazon = getContent.getTagContentWithType(XMLOfOneReview, "link", "amazon.com");
		String linkAmazonUk = getContent.getTagContentWithType(XMLOfOneReview, "link", "amazon.co.uk");
		String linkAmazonCa = getContent.getTagContentWithType(XMLOfOneReview, "link", "amazon.ca");
		String linkLibraryThing = getContent.getTagContentWithType(XMLOfOneReview, "link", "librarything");
		
		if(linkAmazon.compareTo("") != 0)
		{
			linksWhereToBuyBook.add(linkAmazon);
		}
		if(linkAmazonUk.compareTo("") != 0)
		{
			linksWhereToBuyBook.add(linkAmazonUk);
		}
		if(linkAmazonCa.compareTo("") != 0)
		{
			linksWhereToBuyBook.add(linkAmazonCa);
		}
		if(linkLibraryThing.compareTo("") != 0)
		{
			linksWhereToBuyBook.add(linkLibraryThing);
		}
		
		String reviewText = getContent.getTagContent(XMLOfOneReview, "reviewtext");
		reviewText = reviewText.replace("<![CDATA[", "").replace("]]>", "");
		
		
		String allTagsUnited = getContent.getTagContent(XMLOfOneReview, "tags");
		/*the Revish api gives us the tags related to the book review, but they are separated by 
		  a blank space. And they are all united in the same String. Let's get these tags*/
		LinkedList<String> tags = getTagsFromAllTagsUnited(allTagsUnited);
		
		review.setAuthors(authors);
		review.setBookTitle(bookTitle);
		
		review.setReviewId(reviewId);
		review.setIsbn(isbn);
		review.setLinksWhereToBuyBook(linksWhereToBuyBook);
		review.setMediumCover(mediumCover);
		review.setPublisher(publisher);
		review.setRating(rating);
		review.setReviewDate(reviewDate);
		review.setReviewer(reviewer);
		review.setReviewText(reviewText);
		review.setReviewTitle(reviewTitle);
		review.setSmallCover(smallCover);
		review.setUrlReview(urlReview);
		review.setTags(tags);
		
		return review;
	}
	
	private LinkedList<Review> getReviewsFromXMLFromEachReview(LinkedList<String> separateXMLFromEachReview)
	{
		LinkedList<Review> reviews = new LinkedList<Review>();
		for(int i = 0; i < separateXMLFromEachReview.size(); i++)
		{
			String XMLFromOneReview = separateXMLFromEachReview.get(i);
			Review newReview = getReviewFromXML(XMLFromOneReview);
			reviews.add(newReview);
		}
		return reviews;
	}
	
	/**
	 * revish's API doesn't separate book tags associated with reviews found in search, that's 
	 * why we must do this in our system. 
	 * @param allTagsUnited all tags united(not separated) which revish's API returns as result of a search.
	 * @return
	 */
	private LinkedList<String> getTagsFromAllTagsUnited(String allTagsUnited)
	{
		LinkedList<String> separatedTags = new LinkedList<String>();
		String oneTag = "";
		for(int i = 0; i < allTagsUnited.length(); i++)
		{
			char oneChar = allTagsUnited.charAt(i);
			String oneCharInString = String.valueOf(oneChar);
			if(oneCharInString.compareTo(" ") == 0)
			{
				if(oneTag.startsWith("\"") == false || (oneTag.startsWith("\"") == true && oneTag.endsWith("\"") == true) )
				{
					//if one tag starts with ", then it's a compund tag and will only finish with the ending ".
					if((oneTag.startsWith("\"") == true && oneTag.endsWith("\"") == true))
					{
						oneTag = oneTag.substring(1, oneTag.length() - 1);//without " ".
					}
					separatedTags.add(oneTag.toLowerCase());
					oneTag = "";
				}
				
			}
			else
			{
				oneTag = oneTag + oneCharInString;
			}
		}
		
		//there's just one tag that didn't have the space at the end of it.
		if(oneTag.startsWith("\"") && oneTag.endsWith("\""))
		{
			//it's a compound tag, then the " must be removed before adding it
			oneTag = oneTag.substring(1, oneTag.length() - 1);//without " ".
			
		}
		separatedTags.add(oneTag.toLowerCase());
		
		return separatedTags;
	}
	
	private static String reformatUsernameToQuery(String username)
	{
		String userNameToQuery = reformatUsernameToRevishSpecialUsers(username);
		if(userNameToQuery == null)
		{
			userNameToQuery ="";
			for(int i = 0; i < username.length(); i++)
			{
				char usernameChar = username.charAt(i);
				if(usernameChar != '.' && usernameChar != ' ')
				{
					userNameToQuery = userNameToQuery + usernameChar;
				}
			}
			//System.out.println("username to query=" + userNameToQuery);
		}
		
		return userNameToQuery;
		
	}
	
	private static String reformatUsernameToRevishSpecialUsers(String username)
	{
		if(username.compareToIgnoreCase("A. Bowdoin Van Riper") == 0)
		{
			return "abvr";
		}
		else if(username.compareToIgnoreCase("Jack Pickard") == 0)
		{
			return "JackP";
		}
		else if(username.compareToIgnoreCase("Johnnie Walker") == 0)
		{
			return "mrwalker";
		}
		else if(username.compareToIgnoreCase("Blair Millen") == 0)
		{
			return "Blair";
		}
		else if(username.compareToIgnoreCase("Dan Eastwell") == 0)
		{
			return "maskingtape";
		}
		else if(username.compareToIgnoreCase("Sara") == 0)
		{
			return "mutebutton";
		}
		else if(username.compareToIgnoreCase("Sarah Walker") == 0)
		{
			return "bluecat";
		}
		else if(username.compareToIgnoreCase("Dan Smith") == 0)
		{
			return "DanSmithAuthor";
		}
		else if(username.compareToIgnoreCase("Dan Smith") == 0)
		{
			return "DanSmithAuthor";
		}
		else if(username.compareToIgnoreCase("Kate Bolin") == 0)
		{
			return "katemonkey";
		}
		else if(username.compareToIgnoreCase("Susanna") == 0)
		{
			return "pebaline";
		}
		else if(username.compareToIgnoreCase("Tyler Schlagheck") == 0)
		{
			return "tks12dapro";
		}
		else if(username.compareToIgnoreCase("Rob") == 0)
		{
			return "ryal001";
		}
		else if(username.compareToIgnoreCase("Yvonne Pierre") == 0)
		{
			return "ypierre";
		}
		else if(username.compareToIgnoreCase("Elizabeth") == 0)
		{
			return "titania86";
		}
		else if(username.compareToIgnoreCase("marisa") == 0)
		{
			return "meduarte";
		}
		else if(username.compareToIgnoreCase("K.O'Keefe") == 0)
		{
			return "darkelf105";
		}
		else if(username.compareToIgnoreCase("Koty Onoabhagbe") == 0)
		{
			return "Koty1";
		}
		else if(username.compareToIgnoreCase("Daniel Farrey") == 0)
		{
			return "DRF73688";
		}
		else if(username.compareToIgnoreCase("Woo Eun Jung") == 0)
		{
			return "Jung";
		}
		else if(username.compareToIgnoreCase("Tara") == 0)
		{
			return "ptero27";
		}
		else if(username.compareToIgnoreCase("Mary Morgan") == 0)
		{
			return "freeradical";
		}
		else if(username.compareToIgnoreCase("Laurel") == 0)
		{
			return "laurelrobinson";
		}
		else if(username.compareToIgnoreCase("Stephanie M.") == 0)
		{
			return "saturnine13";
		}
		else if(username.compareToIgnoreCase("Leonard Driscoll") == 0)
		{
			return "speakbitterness";
		}
		else if(username.compareToIgnoreCase("Robert A. Boyd") == 0)
		{
			return "TheWrittenWyrd";
		}
		else if(username.compareToIgnoreCase("Wheldon Curzon-Hobson") == 0)
		{
			return "wheldon";
		}
		else if(username.compareToIgnoreCase("Geoff Oldham") == 0)
		{
			return "GeoffO";
		}
		else if(username.compareToIgnoreCase("Andr&eacute; John Haddad0") == 0)
		{
			return "AndreJohnHaddad";
		}
		else if(username.compareToIgnoreCase("Dan Champion") == 0)
		{
			return "danchamp";
		}
		else if(username.compareToIgnoreCase("Paul Kane") == 0)
		{
			return "Paul";
		}
		else if(username.compareToIgnoreCase("Emily") == 0)
		{
			return "devilyn";
		}
		else if(username.compareToIgnoreCase("Hayley Stiles") == 0)
		{
			return "Ikkaii";
		}
		else
		{
			return null;//no, not a special user
		}
	}

}
